<?php

    if (!defined('BASEPATH'))
        exit('No direct script access allowed');

    /**
     * 
     * 
     * Faktori pretrage su:
     * 
     * reservations (provjerava da li je jedinica slobodna u trazenom periodu)
     * maxPS i maxCH provjerava da li je ukupan broj osoba odgovara MAX_PS i maxCH od smjestajne jedinice
     * 
     */
    class SearchPrice {

        private $ci;

        public function __construct() {

            $this->ci = &get_instance();
        }

        private function creationMethod($checkin, $checkout, $Room_ID, $NO_UNITS) {

            $myFactor = new factor();
            $myFactor->setFrom(strtotime($checkin));
            $myFactor->setTo(strtotime($checkout));
            $myFactor->setRoom_ID($Room_ID);
            $myFactor->setNoUnits($NO_UNITS);
            $myFactor->setDayOcurance(new dayOcurance());
            $myFactor->setCompress(new compress());

            $myFactor->setResFinder($this->ci->resFinder);

            return $myFactor;
        }

        public function one_object_rooms($search, $discForPerson, $object, $adults, $ages, $checkin, $checkout) {

            $object_ID = $object['object_ID'];

            $search->setByObjectID($object_ID);

            $rooms = $search->giveRoomsFitMaxPersons();

            if (!empty($rooms)) {
                $cnt_rooms = count($rooms);
                $reindex_rooms = FALSE;
                for ($j = 0; $j < $cnt_rooms; $j++):

                    $unset = FALSE;

                    // check for room max persons and child with discounts
                    $discForPerson->setRoom_id($rooms[$j]['room_ID']);
                    $discForPerson->setNr_adults($adults);
                    foreach ($ages as $age)
                        $discForPerson->setChildsage($age);

                    $freeOfCHargeCH = $discForPerson->findFreeOfChargeNrChildrens();



                    // Find num. of person for Room
                    $ADL = $adults;
                    $CH = count($ages);
                    $PS = $ADL + $CH;

                    // Substract Free of Charge CH
                    if ($rooms[$j]['room_max_ch'] < $freeOfCHargeCH)
                        $freeOfCHargeCH = $rooms[$j]['room_max_ch'];

                    $PS -= $freeOfCHargeCH;

//                    $this->ci->firephp->log('ADL: ' . $ADL);
//                    $this->ci->firephp->log('CH: ' . $CH);
//                    $this->ci->firephp->log('PS: ' . $PS);
//                    $this->ci->firephp->log('--------------------------------');
//                    $this->ci->firephp->log('freeOfCHargeCH: ' . $freeOfCHargeCH);
//                    $this->ci->firephp->log('--------------------------------');
//                    $this->ci->firephp->log('max PS: ' . $rooms[$j]['room_max_person']);
//                    $this->ci->firephp->log('max CH: ' . $rooms[$j]['room_max_ch']);

                    // remove room if room_max_person > persons
//                    if ($rooms[$j]['room_max_person'] < $adults || $rooms[$j]['room_max_ch'] < ( count($ages) - $freeOfCHargeCH))
//                        $unset = TRUE;

                    if ($rooms[$j]['room_max_person'] < $PS)
                        $unset = TRUE;


                    $str_checkin = date('d.m.Y', $checkin);
                    $str_checkout = date('d.m.Y', $checkout);

                    // Check reservations
                    $factor = $this->creationMethod($str_checkin, $str_checkout, $rooms[$j]['room_ID'], $rooms[$j]['room_available_units']);
                    $reservations = $factor->doReservations(TRUE);
                    if ($reservations)
                        $unset = TRUE;



                    // Check stop booking
                    $myStopBooking = new StopBooking();
                    $stop = $myStopBooking->isStop($rooms[$j]['room_ID'], $str_checkin, $str_checkout);

                    if ($stop)
                        $unset = TRUE;

                    // Check release period
                    $myRelease = new ReleasePeriod();
                    $isInRelease = $myRelease->check_release($rooms[$j]['room_ID'], $str_checkin);
//                    if ($isInRelease)
//                        $unset = TRUE;
                    // Unset room
                    if ($unset):
                        unset($rooms[$j]);
                        $reindex_rooms = TRUE;
                    endif;


                endfor;

                if (!empty($rooms)) {
                    if ($reindex_rooms)
                        $rooms = array_values($rooms);

                    return $rooms;
                }
                return FALSE;
            } else
                return FALSE;
        }

        /*
         * Use dependency injection for DiscountsForPerson, DiscountFinder, PriceRowFinder
         * 
         * we can create test for this method and override returning methots with fake ones for ease testing our code
         * we can pass $seasons_ID insted of using $this->objects_has_seasons_model->find_active_seasons_by_room ( $room_ID );
         */

        public function one_room_price($class, $checkin, $checkout, $adults, $ages, $room, $season_ID, $taxes) {

            $room_ID = $room['room_ID'];

            // First find free of charge childrens
            $freeOfCHargeCH = 0;
            if (count($ages) > 0):

                $class['discForPerson']->setDiscountFinderClass($class['d_finder']);

                $class['discForPerson']->setRoom_id($room_ID);
                $class['discForPerson']->setNr_adults($adults);
                foreach ($ages as $age):
                    $class['discForPerson']->setChildsage($age);
                endforeach;

                $freeOfCHargeCH = $class['discForPerson']->findFreeOfChargeNrChildrens();

            endif;


            // find prices
            $prices = $class['prices_model']->find_all_prices($room_ID);

            // find nr_nights and nr_persons
            $nr_nights = calculateDays($checkin, $checkout, TRUE);

            // Sort ages descending - Highest first
            rsort($ages);

            // Find num. of person for Room
            $ADL = $adults;
            $CH = count($ages);
            $PS = $ADL + $CH;

            // Substract Free of Charge CH
            if ($room['room_max_ch'] < $freeOfCHargeCH)
                $freeOfCHargeCH = $room['room_max_ch'];

            $PS -= $freeOfCHargeCH;

            // Move CH to ADL if max CH override
            if ($room['room_max_ch'] < $CH):

                $MOVE_CH = $CH - $room['room_max_ch'];

                for ($mc = 0; $mc < $MOVE_CH; $mc++):
                    unset($ages[$mc]);
                    $ADL++;
                    $CH--;
                endfor;

                $ages = array_values($ages);

            endif;

//            $this->ci->firephp->log('ADL: ' . $ADL);
//            $this->ci->firephp->log('CH: ' . $CH);
//            $this->ci->firephp->log('Ages: ');
//            $this->ci->firephp->log($ages);
//            $this->ci->firephp->log('PS: ' . $PS);
//            
//            $this->ci->firephp->log('--------------------------------');
//            $this->ci->firephp->log('freeOfCHargeCH: ' . $freeOfCHargeCH);
//            $this->ci->firephp->log('--------------------------------');
//            
//            $this->ci->firephp->log('max PS: ' . $room['room_max_person']);
//            $this->ci->firephp->log('max CH: ' . $room['room_max_ch']);
//            $nr_persons = $adults + count($ages) - $freeOfCHargeCH;
            // find periods
            $periods = array();
            for ($i = 1; $i <= $nr_nights; $i++):
                $day = prepareEncreseSearchDate(strtotime($checkin), $i);
                $periods[] = $this->ci->seasons_model->find_active_period_again($season_ID, $day);

            endfor;

            $class['price_r_fnd'] = new PriceRowFinder($nr_nights, $PS, $periods, $prices, $class['classStrparse']);

            $with_prices = $class['price_r_fnd']->find_row_price();

            // Price calculation + discounts
            if (!empty($with_prices)) {

                $class['sellingDiscounts']->setDiscountFinderClass($class['d_finder']);

                $class['sellingDiscounts']->setRoom_id($room_ID);
                $class['sellingDiscounts']->setNr_adults($ADL);
                $class['sellingDiscounts']->setPrice_row($with_prices);
                foreach ($ages as $age):
                    $class['sellingDiscounts']->setChildsage($age);
                endforeach;

                $results = $class['sellingDiscounts']->find_selling_type_and_discount();

                $results['nrpersons'] = $PS;

                unset($class['price_r_fnd']);

                // Add taxes
                $results['total'] = $results['selling_total'] + $taxes;

                return $results;
            } else
                return FALSE;
        }

        public function simpleSearch($objects, $checkin, $checkout, $adults, $ages) {

            // fix bug for checkin checkout
            if (gettype($checkin) == 'string'):
                $checkin = strtotime($checkin);
                $checkout = strtotime($checkout);
            endif;

            $this->ci->load->library('Search');
            loadClass('DiscountsForPerson');
            loadClass('DiscountFinder');

            $discForPerson = new DiscountsForPerson();
            $discForPerson->setDiscountFinderClass(new DiscountFinder());

            $this->ci->search->setCheckin($checkin);
            $this->ci->search->setCheckout($checkout);
            $this->ci->search->setNr_persons($adults);

            $cnt = count($objects);
            $reindex = FALSE;

            // load factor classes and dependencies
            loadClass('presentation/logic/calendar/factor');
            $this->ci->load->model('business/logic/reservationfinder', 'resFinder');
            loadClass('business/logic/reservation/dayOcurance');
            loadClass('business/logic/date/compress');

            // load stopBooking and release period classes
            loadClass('StopBooking');
            loadClass('ReleasePeriod');

            for ($i = 0; $i < $cnt; $i++):

                $rooms = $this->one_object_rooms($this->ci->search, $discForPerson, $objects[$i], $adults, $ages, $checkin, $checkout);

                if (!empty($rooms))
                    $objects[$i]['rooms'] = $rooms;
                else {
                    unset($objects[$i]);
                    $reindex = TRUE;
                }

            endfor;


            if ($reindex)
                $objects = array_values($objects);


            return $objects;
        }

        public function simplePrice($objects, $checkin, $checkout, $adults, $ages) {

            loadClass('DiscountsForPerson');
            loadClass('DiscountFinder');
            loadClass('PriceRowFinder');
            loadClass('SellingTypeAndDiscount');
            $this->ci->load->model('prices_model');
            $this->ci->load->model('objects_has_seasons_model');
            $this->ci->load->model('seasons_model');

            loadClass('tax_calculation', TRUE);
            $this->ci->load->model('tax_model');
            $this->ci->load->helper('tax');

            $cnt = count($objects);
            $reindex = FALSE;
            for ($i = 0; $i < $cnt; $i++):

                $cnt_rooms = count($objects[$i]['rooms']);

                // Find taxes
                $tax_row = $this->ci->tax_model->find_by_object($objects[$i]['object_ID']);
                $objects[$i]['tax'] = $tax_row;
                $tax['total'] = 0;

                if (count($tax_row) > 0 && $tax_row['included']):

                    $nr_nights = calculateDays($checkin, $checkout, TRUE);
                    $tax = find_tax($tax_row, $nr_nights, $adults, $ages);
                    $objects[$i]['tax']['total'] = $tax;

                endif;

                $reindex_rooms = FALSE;

                for ($j = 0; $j < $cnt_rooms; $j++):

                    $room = $objects[$i]['rooms'][$j];

                    $class = $this->givePriceClass();

                    // find active season
                    $season_ID = $class['objectsSeasonModel']->find_active_seasons_by_room($objects[$i]['rooms'][$j]['room_ID']);

                    $result = $this->one_room_price($class, $checkin, $checkout, $adults, $ages, $room, $season_ID, $tax['total']);

                    if (!$result) {
                        unset($objects[$i]['rooms'][$j]);
                        $reindex_rooms = TRUE;
                    } else
                        $objects[$i]['rooms'][$j] = array_merge($objects[$i]['rooms'][$j], $result);


                endfor;

                if (empty($objects[$i]['rooms'])) {
                    unset($objects[$i]);
                    $reindex = TRUE;
                } else {
                    if ($reindex_rooms)
                        $objects[$i]['rooms'] = array_values($objects[$i]['rooms']);

                    // Sort by price DESC
                    sort_array_of_array($objects[$i]['rooms'], 'selling_total', TRUE);
                }

            endfor;

            if ($reindex)
                $objects = array_values($objects);

            return $objects;
        }

        /*
         * load Class for price search
         */

        public function givePriceClass() {

            return array(
                'prices_model' => $this->ci->prices_model,
                'discForPerson' => new DiscountsForPerson (),
                'd_finder' => new DiscountFinder (),
                'sellingDiscounts' => new SellingTypeAndDiscount (),
                'classStrparse' => new strparse (),
                'objectsSeasonModel' => $this->ci->objects_has_seasons_model
            );
        }

    }
    